-- Spyro gem thinker by Tatsuru

local gems = spyro.gems
local spawnedgems = {}
local restoreloot = 0
local dontresetloot

local function BounceThink(mo, deafen)
	if not mo.valid return end

	mo.prevmomz = $ or 0

	if P_MobjFlip(mo) * mo.momz < 0
		mo.prevmomz = mo.momz
	elseif mo.eflags & MFE_JUSTHITFLOOR
		mo.airborne = false
		
		mo.momz = -FixedMul(mo.prevmomz, FixedDiv(deafen*FRACUNIT,20*FRACUNIT))
		
		if gems[mo.type] and mo.momz > FRACUNIT/5
			S_StartSound(mo, sfx_gembnc)
		end
	end
end

local function SparkleSet(mo)
	mo.fuse = 8
	mo.sprite = SPR_SGTW
	mo.scale = mo.target.scale * 2
	mo.color = gems[mo.target.type].color
end

local function SparkleThink(mo)
	if not mo.fuse return end
	
	if (leveltime % 5)
		mo.fuse = $ + 1
	else
		mo.frame = (mo.fuse < 4) and mo.fuse or (8 - mo.fuse)
	end
	
	mo.frame = $ | FF_FULLBRIGHT
	mo.rollangle = $ - ANG2
end

local function GemShine(mo)
	if mo.marked return end
	
	if mo.shine
		if not mo.shine.valid
			mo.shine = nil
		else
			local dist = R_PointToDist(mo.x, mo.y)
			local visscale = (FixedInt(dist) / 1024) + 1
			
			mo.shine.destscale = mo.scale * 2 * visscale
			mo.shine.scalespeed = FRACUNIT/6
		end
	elseif not (leveltime % (TICRATE + P_RandomRange(0, 5))) and P_RandomChance(FRACUNIT/3)
		mo.shine = P_SpawnMobjFromMobj(mo, 0, 0, mo.height/2, MT_SPYRO_GEMSHINE)
		mo.shine.target = mo
		
		SparkleSet(mo.shine)
	end
end

local function GemSpawn(mo)
	mo.sprite = gems[mo.type].sprite
	mo.shadowscale = FRACUNIT
end

local function GemThinker(mo)
	if (leveltime % 3) == 0
		mo.frame = ($ + 1) % gems[mo.type].frames
	end
	
	/*
	if not mo.airborne and not mo.safespot
		mo.safespot = {}
		
		mo.safespot["x"] = mo.x
		mo.safespot["y"] = mo.y
		mo.safespot["z"] = mo.z
	end
	*/
	
	if mo.marked
		mo.timer = $ or 0
		
		if mo.target and mo.target.player and mo.target.player.playerstate == PST_LIVE
			local gotthere = HomingChase(mo, mo.target, (20 + mo.timer*(mo.timer/3))*20000, _, _, mo.thrust, true)
			
			if gotthere return end
			
			if not (leveltime % 1) and mo.timer < 9999
				local sparkle = P_SpawnMobjFromMobj(mo, P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT, P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT, 0, MT_THUNDERCOIN_SPARK)
		
				sparkle.target = mo
				sparkle.scale = FRACUNIT*2
				sparkle.momx = (P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT)
				sparkle.momy = (P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT)
		
				SparkleSet(sparkle)
			end
			
			mo.timer = $ + 1
			mo.thrust = ($ and $ > 0) and $ - 3*FRACUNIT/2 or 0
			mo.rollangle = $ + ANG15
		else
			mo.marked = false
			mo.timer = 0
			mo.momx = 0
			mo.momy = 0
			mo.momz = 0
			mo.rollangle = 0
		end
	end
	
	GemShine(mo)
	BounceThink(mo, 4)
end

local function CreditGem(mo)
	if mo.spawnpoint
		table.insert(spawnedgems, #mo.spawnpoint)
	end
	
	if mo.basket
		mo.basket.angle = $ - gems[mo.type].value
	end
	
	spyro.loot = $ + gems[mo.type].value
end

local function GemTouch(mo, toucher)
	if toucher.player.bot == 1 return true end
	if mo.airborne return true end
	
	if mo.marked and toucher != mo.target return true end
	
	--local spark = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_SPARK)
	--spark.color = gems[mo.type].color
	--spark.colorized = true
	
	local num = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_SPYRO_NUM)
	num.momx = mo.momx/8
	num.momy = mo.momy/8
	num.sprite = gems[mo.type].numsprite
	num.scale = 3*FRACUNIT/2
	num.fuse = 3*TICRATE
	num.momz = 12*FRACUNIT
	
	for i = 1, P_RandomRange(4, 8)
		local sparkle = P_SpawnMobjFromMobj(mo, P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT, P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT, 0, MT_SPYRO_GEMSHINE)
		
		sparkle.target = mo
		sparkle.momx = (P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT)
		sparkle.momy = (P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT)
		sparkle.momz = (P_RandomChance(FRACUNIT/2) and FRACUNIT or -FRACUNIT)
		
		SparkleSet(sparkle)
	end
	
	CreditGem(mo)
end

local function GemCollide(mo, line)
	if mo.marked return end

	if line.flags & ML_BLOCKMONSTERS return true end
	
	for _, s in ipairs({line.frontsector, line.backsector})
		for fof in s.ffloors()
			if not HeightCheck(mo.z, mo.z + mo.height, fof.bottomheight, fof.topheight)
				continue
			end
			
			if not (fof.master.flags & ML_BLOCKMONSTERS)
				continue
			end
			
			return true
		end
	end
end

local function GemRespawn(mo)
	if P_CheckDeathPitCollide(mo)
		CreditGem(mo)
	end
end

for i = MT_SPYRO_REDGEM, MT_SPYRO_MAGENTAGEM
	addHook("MobjSpawn", GemSpawn, i)
	addHook("MobjThinker", GemThinker, i)
	addHook("TouchSpecial", GemTouch, i)
	addHook("MobjLineCollide", GemCollide, i)
	addHook("MobjRemoved", GemRespawn, i)
	addHook("MapThingSpawn", function(mo, mapt)
		for _, v in pairs(spawnedgems)
			if #mapt == v
				restoreloot = $ + gems[mo.type].value
				P_RemoveMobj(mo)
				return true
			end
		end
	end, i)
end

addHook("MobjThinker", function(mo)
	BounceThink(mo, 17)
end, MT_SPYRO_NUM)

addHook("MobjThinker", SparkleThink, MT_SPYRO_GEMSHINE)

-- Shit so Single Player can cope with gems being collected
addHook("MapLoad", do
	spyro.loot = $ + restoreloot
	restoreloot = 0
end)

addHook("MapChange", function(mapnum)
	if mapheaderinfo[mapnum].lvlttl == "Snowflake Ridge"
		if not dontresetloot
			spawnedgems = {}
		end
		
		dontresetloot = true
	else
		dontresetloot = false
	end
end)